package com.zheng.sms.aliyun;

import com.aeye.mbr.common.util.RedisUtil;
import com.aeye.mbr.common.util.TimeUtils;
import com.aeye.mbr.sms.SmsContext;
import com.aeye.mbr.upms.dao.model.SmsLog;
import com.aeye.mbr.sms.exception.SmsException;
import com.alibaba.fastjson.JSON;
import com.aliyuncs.DefaultAcsClient;
import com.aliyuncs.IAcsClient;
import com.aliyuncs.dysmsapi.model.v20170525.QuerySendDetailsRequest;
import com.aliyuncs.dysmsapi.model.v20170525.QuerySendDetailsResponse;
import com.aliyuncs.dysmsapi.model.v20170525.SendSmsRequest;
import com.aliyuncs.dysmsapi.model.v20170525.SendSmsResponse;
import com.aliyuncs.exceptions.ClientException;
import com.aliyuncs.profile.DefaultProfile;
import com.aliyuncs.profile.IClientProfile;
import com.zheng.sms.rpc.api.SmsSender;
import com.zheng.sms.rpc.service.SmsLogService;
import com.zheng.sms.rpc.service.impl.SmsApiServiceImpl;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang3.RandomUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.CollectionUtils;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.LinkedHashMap;
import java.util.Map;

/**
 * 短信API产品的DEMO程序,工程中包含了一个SmsDemo类，直接通过
 * 执行main函数即可体验短信产品API功能(只需要将AK替换成开通了云通信-短信产品功能的AK即可)
 * 工程依赖了2个jar包(存放在工程的libs目录下)
 * 1:aliyun-java-sdk-core.jar
 * 2:aliyun-java-sdk-dysmsapi.jar
 * <p>
 * 备注:Demo工程编码采用UTF-8
 * 国际短信发送请勿参照此DEMO
 */
public class AliyunSmsSenderImpl implements SmsSender {

    private static Logger log = LoggerFactory.getLogger(AliyunSmsSenderImpl.class);

    @Autowired
    SmsLogService smsLogService;

    //产品名称:云通信短信API产品,开发者无需替换
    static final String product = "Dysmsapi";
    //产品域名,开发者无需替换
    static final String domain = "dysmsapi.aliyuncs.com";


    static final String TIMEOUT = "10000";

    public AliyunSmsSenderImpl() {
        //可自助调整超时时间
        System.setProperty("sun.net.client.defaultConnectTimeout", TIMEOUT);
        System.setProperty("sun.net.client.defaultReadTimeout", TIMEOUT);
    }


    private IAcsClient getAcsClient(SmsContext context) throws ClientException {
        //初始化acsClient,暂不支持region化
        IClientProfile profile = DefaultProfile.getProfile("cn-hangzhou", context.getAppId(), context.getAppSecret());
        DefaultProfile.addEndpoint("cn-hangzhou", "cn-hangzhou", product, domain);
        IAcsClient acsClient = new DefaultAcsClient(profile);
        return acsClient;
    }


    public static QuerySendDetailsResponse querySendDetails(String bizId, SmsContext context) throws ClientException {

        //可自助调整超时时间
        System.setProperty("sun.net.client.defaultConnectTimeout", "10000");
        System.setProperty("sun.net.client.defaultReadTimeout", "10000");

        //初始化acsClient,暂不支持region化
        IClientProfile profile = DefaultProfile.getProfile("cn-hangzhou", context.getAppId(), context.getAppSecret());
        DefaultProfile.addEndpoint("cn-hangzhou", "cn-hangzhou", product, domain);
        IAcsClient acsClient = new DefaultAcsClient(profile);

        //组装请求对象
        QuerySendDetailsRequest request = new QuerySendDetailsRequest();
        //必填-号码
        request.setPhoneNumber("15000000000");
        //可选-流水号
        request.setBizId(bizId);
        //必填-发送日期 支持30天内记录查询，格式yyyyMMdd
        SimpleDateFormat ft = new SimpleDateFormat("yyyyMMdd");
        request.setSendDate(ft.format(new Date()));
        //必填-页大小
        request.setPageSize(10L);
        //必填-当前页码从1开始计数
        request.setCurrentPage(1L);

        //hint 此处可能会抛出异常，注意catch
        QuerySendDetailsResponse querySendDetailsResponse = acsClient.getAcsResponse(request);

        return querySendDetailsResponse;
    }


    @Override
    public void sendTemplateSms(String mobile, LinkedHashMap<String, String> params) {
        SmsContext context = SmsApiServiceImpl.getContext();
        String today = TimeUtils.formatTime(new Date(), "yyyyMMdd");
        StringBuilder builder = new StringBuilder();
        builder.append("count-");
        builder.append(context.getTopOrgId()).append("-").append(context.getSmsConfigId()).append("-").append(mobile);
        builder.append("-").append(today);
        String allKey = builder.toString();
        builder.append("-").append(context.getTemplateType());
        String templateKey = builder.toString();
        String cacheCount = RedisUtil.get(allKey);
        Integer allCount = null;
        if (cacheCount != null) {
            allCount = Integer.valueOf(cacheCount);
        }
        if (allCount == null) {
            allCount = 0;
        }
        Integer maxTotalCount = context.getMaxTotalCount();

        if (maxTotalCount != null && maxTotalCount > 0 && allCount >= maxTotalCount) {
            throw new SmsException("该手机号码达到今日上限!");
        }

        cacheCount = RedisUtil.get(templateKey);
        Integer templateCount = null;
        if (cacheCount != null) {
            templateCount = Integer.valueOf(cacheCount);
        }


        if (templateCount == null) {
            templateCount = 0;
        }

        Integer maxTemplateCount = context.getMaxTemplateCount();
        if (maxTemplateCount != null && maxTemplateCount > 0 && templateCount >= maxTemplateCount) {
            throw new SmsException("该手机号码达到今日上限!");
        }

        if (params != null) {
            //
            SmsLog smsLog = new SmsLog();
            smsLog.setTemplateId(context.getTemplateId());
            smsLog.setSmsConfigId(context.getSmsConfigId());
            smsLog.setMobile(mobile);
            smsLog.setTopOrgId(context.getTopOrgId());
            smsLog.setTemplateType(context.getTemplateType());
            smsLog.setIp(context.getIp());
            smsLog.setStatus(SmsLog.STATUS_CREATED);
            //合并内容
            smsLog.setContent(merge(context.getContent(), params));
            smsLogService.insertSelective(smsLog);
            try {
                //组装请求对象-具体描述见控制台-文档部分内容
                SendSmsRequest request = new SendSmsRequest();
                //必填:待发送手机号
                request.setPhoneNumbers(mobile);
                //必填:短信签名-可在短信控制台中找到
                request.setSignName(context.getSignName());
                //必填:短信模板-可在短信控制台中找到
                request.setTemplateCode(context.getTemplateId());
                //可选:模板中的变量替换JSON串,如模板内容为"亲爱的${name},您的验证码为${code}"时,此处的值为
                request.setTemplateParam(JSON.toJSONString(params));
                if (context.containsKey("extendCode")) {
                    //选填-上行短信扩展码(无特殊需求用户请忽略此字段)
                    request.setSmsUpExtendCode((String) context.getAttribute("extendCode"));
                }
                if (context.containsKey("outId")) {
                    //可选:outId为提供给业务方扩展字段,最终在短信回执消息中将此值带回给调用者
                    request.setOutId((String) context.getAttribute("outId"));
                }
                //hint 此处可能会抛出异常，注意catch
                SendSmsResponse response = getAcsClient(context).getAcsResponse(request);
                if (response.getCode() != null && "OK".equals(response.getCode())) {
                    smsLogService.updateLogStatus(smsLog.getId(), SmsLog.STATUS_SEND_SUCCESS);
                } else {
                    throw new SmsException("短信发送失败!"+response.getMessage());
                }
            } catch (Exception e) {
                log.error("发送短信失败!手机号码:" + mobile + "\t模板ID:" + context, e);
                smsLogService.updateLogStatus(smsLog.getId(), SmsLog.STATUS_SEND_FAILED);
                throw new SmsException(e);
            } finally {
                allCount++;
                templateCount++;
                RedisUtil.set(allKey, "" + allCount, 24 * 60 * 60);
                RedisUtil.set(templateKey, "" + templateCount, 24 * 60 * 60);
            }
        }
    }

    @Override
    public void sendTemplateSms(String mobile, String content) {

    }


    public String sendVerifyCode(String mobile, int length) {
        SmsContext context = SmsApiServiceImpl.getContext();
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < length; i++) {
            sb.append(RandomUtils.nextInt(0, 10));
        }
        String code = sb.toString();
        if (context.getExpireTime() != null && context.getExpireTime() > 0) {
            StringBuilder builder = new StringBuilder();
            builder.append("code-");
            builder.append(context.getTopOrgId()).append("-").append(context.getSmsConfigId()).append("-").append(mobile);
            builder.append("-").append(context.getTemplateType());
            RedisUtil.set(builder.toString(), code, context.getExpireTime());
        }
        LinkedHashMap<String, String> params = new LinkedHashMap<>();
        params.put("number", code);
        sendTemplateSms(mobile, params);
        return code;
    }


    @Override
    public boolean checkSmsCode(String mobile, String code, String type) {
        SmsContext context = SmsApiServiceImpl.getContext();
        StringBuilder builder = new StringBuilder();
        builder.append("code-");
        builder.append(context.getTopOrgId()).append("-").append(context.getSmsConfigId()).append("-").append(mobile);
        builder.append("-").append(context.getTemplateType());
        String cacheCode = RedisUtil.get(builder.toString());
        return code.equalsIgnoreCase(cacheCode);
    }

    @Override
    public void clearSmsCode(String mobile, String type) {
        SmsContext context = SmsApiServiceImpl.getContext();
        StringBuilder builder = new StringBuilder();
        builder.append("code-");
        builder.append(context.getTopOrgId()).append("-").append(context.getSmsConfigId()).append("-").append(mobile);
        builder.append("-").append(context.getTemplateType());
        RedisUtil.remove(builder.toString());
    }

    /**
     * 合并模板内容
     *
     * @param content
     * @param params
     * @return
     */
    private String merge(String content, Map<String, String> params) {
        if (StringUtils.isNotBlank(content) && !CollectionUtils.isEmpty(params)) {
            for (String key : params.keySet()) {
                content = content.replace("${" + key + "}", params.get(key));
            }
        }
        return content;
    }


}
